package com.han.yrpc.registrycenter.localcache;

import com.han.yrpc.core.SingletonFactory;
import com.han.yrpc.core.registry.Register;
import com.han.yrpc.core.registry.ServiceDiscovery;
import com.han.yrpc.core.registry.ServiceInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;

@Slf4j
public class SimpleServiceDiscover implements ServiceDiscovery {

    private final Register register;

    public SimpleServiceDiscover() {
        register = SingletonFactory.getSingleton(LocalcacheRegister.class);
    }

    @Override
    public ServiceInfo discover(String serviceName) {
        /**
         * todo
         * 1. 负载均衡
         * 2. 每一次都要去查是不是性能很差，消费者本地可以缓存一份服务信息，这样也是注册中心的高可用了
         * 3. 本地缓存一份服务信息的话，服务有更新怎么办，比如服务版本变了，扩容了等等怎么办，怎么样保持与注册中心的一致性，心跳机制，
         *    虽然k8s service可以自动负载，但是如果我是多集群怎么办，要做异地、容灾呢。
         *    所以有时候会说，在云原生时代，spring cloud的一些功能k8s作为基础设施已经提供了，如果两者都用的话，会存在冲突，
         *    比如，spring重试设置了5次，k8s也设置了5次，但是实际上会重试 5*5=25 次。
         * 4.
         */
        return getService(serviceName);
    }

    private ServiceInfo getService(String serviceName) {
        Socket socket = new Socket();
        try {
            socket.connect(register.getInetSocketAddress());
            ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
            outputStream.writeBoolean(false);
            outputStream.writeUTF(serviceName);
            outputStream.flush();

            Object object = inputStream.readObject();
            Set<ServiceInfo> set = (Set<ServiceInfo>) object;
            List<ServiceInfo> list = new ArrayList<>(set);
            ServiceInfo serviceInfo = list.get(new Random().nextInt(list.size()));
            log.info("discover service[{},{},{}]", serviceName, serviceInfo.getHost(), serviceInfo.getPort());
            return serviceInfo;

        } catch (IOException | ClassNotFoundException e) {
            log.error("errorororor");
        } finally {
            try {
                socket.close();
            } catch (IOException e) {

            }
        }
        return null;
    }
}
